package drds.plus.sql_process.parser;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import drds.plus.common.Constants;
import drds.plus.common.lifecycle.AbstractLifecycle;
import drds.plus.parser.SqlParser;
import drds.plus.parser.abstract_syntax_tree.statement.Statement;
import drds.plus.sql_process.parser.visitor.ParameterizedVistor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

@Slf4j
public class SqlParseManagerImpl extends AbstractLifecycle implements SqlParseManager {
    @Override
    public Logger log() {
        return log;
    }

    private static Cache<String, ParseResult> sqlToParseResultCache = null;
    private long cacheSize = 1000;
    private long expireTime = Constants.DEFAULT_OPTIMIZER_EXPIRE_TIME;

    protected void doInit() {
        sqlToParseResultCache = CacheBuilder.newBuilder().maximumSize(cacheSize).expireAfterWrite(expireTime, TimeUnit.MILLISECONDS).softValues().build();
    }

    protected void doDestroy() {
        sqlToParseResultCache.invalidateAll();
    }

    public ParseInfo parse(final String sql, boolean cached) {
        ParseResult parseResult = null;
        try {
            // 只缓存sql的解析结果
            if (cached) {
                parseResult = sqlToParseResultCache.get(sql, new Callable<ParseResult>() {

                    public ParseResult call() throws Exception {
                        return parse(sql);
                    }

                });
            } else {
                parseResult = parse(sql);
            }
        } catch (RuntimeException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
        // AstNode visitor结果不能做缓存
        ParseInfoImpl parseInfo = new ParseInfoImpl();
        parseInfo.build(sql, parseResult.statement, parseResult.parameterizedSql);
        return parseInfo;

    }

    private ParseResult parse(String sql) {
        ParseResult parseResult = new ParseResult();
        Statement statement = SqlParser.parse(sql);
        parseResult.statement = statement;

        StringBuilder sb = new StringBuilder();
        ParameterizedVistor parameterizedVistor = new ParameterizedVistor(sb);
        statement.accept(parameterizedVistor);
        parseResult.parameterizedSql = parameterizedVistor.getSql();
        return parseResult;
    }

    public void setCacheSize(long cacheSize) {
        this.cacheSize = cacheSize;
    }

    public void setExpireTime(long expireTime) {
        this.expireTime = expireTime;
    }

}
